{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "b256f943",
   "metadata": {},
   "source": [
    "## 生成器"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "552b7c8b",
   "metadata": {},
   "source": [
    "### 基本概念\n",
    "在Python中，一边循环一边计算的机制，称为生成器：generator\n",
    "\n",
    "**为什么要有生成器？**\n",
    "\n",
    "列表所有数据都在内存中，如果有海量数据的话将会非常耗内存。\n",
    "如：仅仅需要访问前面几个元素，那后面绝大多数元素占用的空间都白白浪费了。\n",
    "\n",
    "如果列表元素按照某种算法推算出来，那我们就可以在循环的过程中不断推算出后续的元素，这样就不必创建完整的list，从而节省大量的空间。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0c15ad75",
   "metadata": {},
   "source": [
    "简单说：用时间换空间，想要得到庞大的数据，又想让它占用空间少，那就用生成器"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8d4cbda0",
   "metadata": {},
   "source": [
    "### 创建生成器--生成器表达式"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "f5b50d00",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T03:39:15.167151Z",
     "start_time": "2023-10-13T03:39:15.161868Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]\n",
      "<generator object <genexpr> at 0x106269580>\n",
      "0\n",
      "1\n",
      "4\n",
      "9\n",
      "16\n"
     ]
    }
   ],
   "source": [
    "# 创建列表\n",
    "L = [x * x for x in range(10)]\n",
    "print(L)\n",
    "\n",
    "# 创建生成器\n",
    "g = (x * x for x in range(10))\n",
    "print(g) # <generator object <genexpr> at 0x1022ef630>\n",
    "\n",
    "# 获取生成器内的数据\n",
    "print(g.__next__())\n",
    "print(g.__next__())\n",
    "print(g.__next__())\n",
    "print(g.__next__())\n",
    "print(g.__next__())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "df359ce2",
   "metadata": {},
   "source": [
    "### 创建生成器--生成器函数"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "66799324",
   "metadata": {},
   "source": [
    "**生成器函数：**\n",
    "\n",
    "- 如果一个函数中包含 yield 关键字，那么这个函数就不再是一个普通函数，调用函数就是创建了一个（generator）对象。\n",
    "\n",
    "- 生成器函数：其实就是利用关键字 yield 一次性返回一个结果，阻塞，重新开始"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "78de2b23",
   "metadata": {},
   "source": [
    "**生成器函数的工作原理：**\n",
    "\n",
    "- 生成器函数返回一个迭代器，for循环对这个迭代器不断调用 __next__() 函数，不断运行到下一个yield 语句，一次一次取得每一个返回值，直到没有 yield 语句为止，最终引发 StopIteration 异常。\n",
    "\n",
    "\n",
    "- yield 相当于 return 返回一个值，并且记住这个返回的位置，下次迭代时，代码从 yield 的下一条语句(不一定是下一行)开始执行。\n",
    "\n",
    "\n",
    "- send() 和 next() 一样，都能让生成器继续往下走一步（下次遇到 yield 停），但 send() 能传一个值，这个值作为 yield 表达式整体的结果"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "32a5441c",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T03:47:53.021021Z",
     "start_time": "2023-10-13T03:47:52.990403Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<generator object test at 0x1100b86d0>\n",
      "start\n",
      "a.__next__ = 0\n",
      "temp = None\n",
      "i = 0\n",
      "------------------\n",
      "a.__next__ = 1\n",
      "temp = None\n",
      "i = 1\n",
      "------------------\n",
      "a.__next__ = 2\n",
      "temp = None\n",
      "i = 2\n",
      "------------------\n",
      "end\n"
     ]
    },
    {
     "ename": "StopIteration",
     "evalue": "done",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mStopIteration\u001b[0m                             Traceback (most recent call last)",
      "Input \u001b[0;32mIn [7]\u001b[0m, in \u001b[0;36m<cell line: 29>\u001b[0;34m()\u001b[0m\n\u001b[1;32m     33\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124ma.__next__ =\u001b[39m\u001b[38;5;124m'\u001b[39m, a\u001b[38;5;241m.\u001b[39m\u001b[38;5;21m__next__\u001b[39m())\n\u001b[1;32m     34\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124ma.__next__ =\u001b[39m\u001b[38;5;124m'\u001b[39m, a\u001b[38;5;241m.\u001b[39m\u001b[38;5;21m__next__\u001b[39m())\n\u001b[0;32m---> 36\u001b[0m \u001b[43ma\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[38;5;21;43m__next__\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n",
      "\u001b[0;31mStopIteration\u001b[0m: done"
     ]
    }
   ],
   "source": [
    "# coding=utf-8\n",
    "\"\"\"\n",
    "1. 函数有了yield之后，调用它，就会生成一个生成器\n",
    "2. yield作用：程序挂起，返回相应的值。下次从下一个语句开始执行。\n",
    "3. return在生成器中代表生成器终止，直接报错：StopIeratation\n",
    "4. next方法作用：唤醒并继续执行\n",
    "\"\"\"\n",
    "\n",
    "\n",
    "def test():\n",
    "    print(\"start\")\n",
    "    \n",
    "    i = 0\n",
    "    while i < 3:\n",
    "        # yield i\n",
    "        temp = yield i\n",
    "\n",
    "        print(f\"temp = {temp}\")\n",
    "\n",
    "        print(f\"i = {i}\")\n",
    "\n",
    "        print('------------------')\n",
    "        i += 1\n",
    "        \n",
    "    print(\"end\")\n",
    "    return \"done\"\n",
    "\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    a = test()\n",
    "    print(a)\n",
    "    print('a.__next__ =', a.__next__())\n",
    "    print('a.__next__ =', a.__next__())\n",
    "    print('a.__next__ =', a.__next__())\n",
    "    \n",
    "    a.__next__()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3b7e7d69",
   "metadata": {},
   "source": [
    "### send函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "997e8444",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T03:54:10.265160Z",
     "start_time": "2023-10-13T03:54:10.258337Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "start\n",
      "0\n",
      "================\n",
      "temp = 100\n",
      "---------------\n",
      "1\n",
      "temp = None\n",
      "---------------\n",
      "2\n",
      "================\n",
      "temp = None\n",
      "---------------\n",
      "in  3\n",
      "temp = None\n",
      "---------------\n",
      "end\n"
     ]
    }
   ],
   "source": [
    "def foo():\n",
    "    print(\"start\")\n",
    "    i = 0\n",
    "    while i < 4:\n",
    "        temp = yield i\n",
    "        print(f\"temp = {temp}\")\n",
    "        \n",
    "        print('---------------')\n",
    "        i = i+1\n",
    "    print(\"end\")\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    \n",
    "    # 返回一个生成器\n",
    "    g = foo()\n",
    "    print(next(g))  # g.__next__()\n",
    "    \n",
    "    print(\"================\")\n",
    "    \n",
    "    # send的作用是唤醒并继续执行，发送一个信息到生成器内部，由temp接收\n",
    "    print(g.send(100))\n",
    "    \n",
    "    # 继续执行\n",
    "    print(next(g))\n",
    "    print(\"================\")\n",
    "    \n",
    "    # 相当于 next\n",
    "    for a in g:\n",
    "        print(\"in \", a)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "aa0a3f69",
   "metadata": {},
   "source": [
    "## 迭代器"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3208dc3e",
   "metadata": {},
   "source": [
    "### 基本概念"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "682532c7",
   "metadata": {},
   "source": [
    "\n",
    "1. 迭代是Python最强大的功能之一，是访问集合元素的一种方式。\n",
    "1. 迭代器是一个可以记住遍历的位置的对象。\n",
    "1. 迭代器对象从集合的第一个元素开始访问，直到所有的元素被访问完结束。\n",
    "1. 迭代器只能往前不会后退。\n",
    "1. 迭代器有两个基本的方法： iter()  和  next() "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e3ebf4a9",
   "metadata": {},
   "source": [
    "**可迭代对象和迭代器区别：**\n",
    "\n",
    "1. 一个实现了 iter 方法的对象，称为 \"可迭代对象Ieratable\"\n",
    "2. 一个实现 next 方法并且是可迭代的对象，称为\"迭代器Iterator\"，即：实现了 iter 方法和 next 方法的对象就是迭代器。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d24b3c20",
   "metadata": {},
   "source": [
    "**注意：**\n",
    "\n",
    "生成器都是 Iterator 对象，但list、dict、str 虽然是 Iterable（可迭代对象） ，却不是 Iterator（迭代器）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "56faa9ef",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T04:02:17.470011Z",
     "start_time": "2023-10-13T04:02:17.464644Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n",
      "False\n"
     ]
    }
   ],
   "source": [
    "\"\"\"判断是否是 迭代器 或者 迭代对象\"\"\"\n",
    "from collections.abc import Iterator\n",
    "from collections.abc import Iterable\n",
    "\n",
    "# 判断 列表 是否是可迭代的\n",
    "result = isinstance([], Iterable)\n",
    "print(result)\n",
    "\n",
    "# 判断 列表 是否是迭代器\n",
    "result = isinstance([], Iterator)\n",
    "print(result)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "88346dbd",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T04:03:29.385376Z",
     "start_time": "2023-10-13T04:03:29.371663Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "\"\"\"list、dict、str等 Iterable 变成 Iterator,可以使用 iter() 函数\"\"\"\n",
    "isinstance(iter([]), Iterator)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "17390412",
   "metadata": {},
   "source": [
    "![](images/2.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "74177fbf",
   "metadata": {},
   "source": [
    "### for循环的本质"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "f76182c2",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T04:07:24.399390Z",
     "start_time": "2023-10-13T04:07:24.396633Z"
    }
   },
   "outputs": [],
   "source": [
    "# Python的 for 循环本质上就是通过不断调用 next() 函数实现的\n",
    "for x in [1, 2, 3, 4, 5]:\n",
    "    pass"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "17bca7c6",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T04:07:30.872322Z",
     "start_time": "2023-10-13T04:07:30.866887Z"
    }
   },
   "outputs": [],
   "source": [
    "# 本质是：\n",
    "# 首先获得Iterator对象:\n",
    "it = iter([1, 2, 3, 4, 5])\n",
    "\n",
    "# 循环:\n",
    "while True:\n",
    "    try:\n",
    "        # 获得下一个值:\n",
    "        x = next(it)\n",
    "        \n",
    "    # 遇到 StopIteration 就退出循环\n",
    "    except StopIteration:\n",
    "        break"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bf4cff61",
   "metadata": {},
   "source": [
    "### 创建一个迭代器\n",
    "一个类作为一个迭代器使用需要在类中实现两个方法 __iter__() 与 __next__()：\n",
    "- __iter__() 方法返回一个特殊的迭代器对象， 这个迭代器对象实现了，__next__() 方法并通过StopIteration 异常标识迭代的完成。\n",
    "- __next__() 方法会返回下一个迭代器对象。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "1a865033",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T04:11:27.118256Z",
     "start_time": "2023-10-13T04:11:27.112980Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "10\n",
      "20\n",
      "30\n"
     ]
    }
   ],
   "source": [
    "class MyNumbers:\n",
    "    def __iter__(self):\n",
    "        self.num = 10\n",
    "        return self\n",
    "\n",
    "    def __next__(self):\n",
    "        if self.num < 40:\n",
    "            x = self.num\n",
    "            self.num += 10\n",
    "            return x\n",
    "        else:\n",
    "            raise StopIteration\n",
    "\n",
    "# 创建对象\n",
    "myclass = MyNumbers()\n",
    "\n",
    "# 生成迭代器\n",
    "myiter = iter(myclass)\n",
    "\n",
    "# 获取内容\n",
    "print(next(myiter))\n",
    "print(next(myiter))\n",
    "print(next(myiter))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8f0eecc5",
   "metadata": {},
   "source": [
    "## 动态添加属性和方法"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6701754e",
   "metadata": {},
   "source": [
    "![1](images/3.png)\n",
    "动态编程语言是高级程序设计语言的一个类别，在计算机科学领域已被广泛应用。\n",
    "\n",
    "它是指在运行时可以改变其结构的语言 ：例如新的函数、 对象、甚至代码可以被引进，已有的函数可以被删除或是其他结构上的变化。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "7be0a450",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T04:15:05.767413Z",
     "start_time": "2023-10-13T04:15:05.762360Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "100\n",
      "zhangsan, running...\n"
     ]
    }
   ],
   "source": [
    "\"\"\"动态给对象、类添加属性和方法\"\"\"\n",
    "import types\n",
    "\n",
    "\n",
    "class Person():\n",
    "    def __init__(self, name, age):\n",
    "        self.name = name\n",
    "        self.age = age\n",
    "\n",
    "\n",
    "p1 = Person(\"zhangsan\", 20)\n",
    "p2 = Person(\"lisi\", 30)\n",
    "\n",
    "# 动态给对象添加属性\n",
    "p1.score = 100\n",
    "print(p1.score)\n",
    "\n",
    "\n",
    "def run(self):\n",
    "    print(f\"{self.name}, running...\")\n",
    "\n",
    "# 动态给对象添加方法\n",
    "p1.run = types.MethodType(run, p1)\n",
    "p1.run()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "2f45522b",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T04:18:01.290889Z",
     "start_time": "2023-10-13T04:18:01.285537Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "---static method---\n",
      "---cls method---\n"
     ]
    }
   ],
   "source": [
    "\"\"\"给类动态添加静态方法以及类方法\"\"\"\n",
    "\n",
    "class Person():\n",
    "    pass\n",
    "\n",
    "# 添加静态方法\n",
    "@staticmethod\n",
    "def staticfunc():\n",
    "    print(\"---static method---\")\n",
    "\n",
    "Person.staticfunc = staticfunc\n",
    "Person.staticfunc()\n",
    "Person.score = 1000\n",
    "\n",
    "# 添加类方法\n",
    "@classmethod\n",
    "def clsfunc(cls):\n",
    "    print('---cls method---')\n",
    "    \n",
    "Person.clsfunc = clsfunc\n",
    "Person.clsfunc()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "583609f0",
   "metadata": {},
   "source": [
    "**__slots__ 的作用：**\n",
    "1. __slots__ 对动态添加成员变量、成员方法有限制。对动态添加类属性、类方法没有限制。\n",
    "2. __slots__ 只对本类有限制，不限制子类"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "8bcb1d50",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T07:18:08.566386Z",
     "start_time": "2023-10-13T07:18:08.535484Z"
    },
    "collapsed": true
   },
   "outputs": [
    {
     "ename": "AttributeError",
     "evalue": "'Person' object has no attribute 'gender'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
      "Input \u001b[0;32mIn [19]\u001b[0m, in \u001b[0;36m<cell line: 13>\u001b[0;34m()\u001b[0m\n\u001b[1;32m     13\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;18m__name__\u001b[39m \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m__main__\u001b[39m\u001b[38;5;124m'\u001b[39m:\n\u001b[1;32m     14\u001b[0m     p1 \u001b[38;5;241m=\u001b[39m Person(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mzxy\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;241m18\u001b[39m)\n\u001b[0;32m---> 15\u001b[0m     p1\u001b[38;5;241m.\u001b[39mgender \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mman\u001b[39m\u001b[38;5;124m\"\u001b[39m\n",
      "\u001b[0;31mAttributeError\u001b[0m: 'Person' object has no attribute 'gender'"
     ]
    }
   ],
   "source": [
    "# coding=utf-8\n",
    "class Person():\n",
    "    # 限制动态添加类属性、类方法\n",
    "    __slots__ = {\"name\", \"age\"}\n",
    "\n",
    "    def __init__(self, name, age):\n",
    "        self.name = name\n",
    "        self.age = age\n",
    "\n",
    "    def eat(self):\n",
    "        print(\"人是铁饭是钢，要吃！\")\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    p1 = Person(\"zxy\", 18)\n",
    "    p1.gender = \"man\"  # AttributeError: 'Person' object has no attribute 'gender'\n",
    "    \n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9d920d65",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "125753c6",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.12"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {
    "height": "calc(100% - 180px)",
    "left": "10px",
    "top": "150px",
    "width": "248.1875px"
   },
   "toc_section_display": true,
   "toc_window_display": true
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
